﻿#pragma once
#include "LuaCommon.h"
#include "LuaStackOps.h"

class LuaObjectImpl;
class LuaTable;

class LUAOBJ_API LuaObject
{
public:
	LuaObject();
	LuaObject(LuaState* L);
	LuaObject(LuaState* L,int idx);
	LuaObject(LuaObjectImpl* impl);
	LuaObject(const LuaObject& rfs);
	~LuaObject();

	int getIndex()const;

	//类型判断
	const char* typeName()const;
	int  getType()const;
	bool isNumber()const;
	bool isString()const;
	bool isCFunction()const;
	bool isFunction()const;
	bool isUData()const;
	bool isTable()const;
	bool isNil()const;
	bool isValid()const;

	bool isBool()const;
	bool isThread()const;
	bool isNone()const;

	//lightudata
	bool isPtr()const;

	//to
	lua_Number   toNumber()const;
	float		 toFloat()const;
	lua_Integer  toInt()const;
	lua_Unsigned toUInt()const;

	int32_t      toInt32()const;
	uint32_t     toUInt32()const;

	bool		 toBool()const;
	const char*  toString()const;
	const char*  toString(size_t *len)const;

	std::wstring toWString()const;

	lua_CFunction toCFunction()const;
	void *		 toData()const;

	lua_State*   toThread()const;
	const void*  toPtr()const;

	//转为常量值
	size_t       toConst(const LuaConstDef* tags, size_t def = 0)const;

	//返回数组的元素个数，字符串的长度，userdata所占字节数等
	size_t		 objLen()const;

	//操作符
	LuaObject& operator=(const LuaObject& other);

	//比较
	bool operator==(lua_Integer n);
	bool operator==(const char* s);
	bool operator==(const LuaObject& other);
	bool operator<(const LuaObject& other);

	operator bool()const{
		return toBool();
	}

	lua_State* getLuaState() const;
	LuaState* getCppLuaState() const;

	bool setMetatable(LuaTable tab);
	LuaTable getMetatable() const;

	template <class T>
	bool setUpValue(int n, T arg);
	LuaObject getUpValue(int n) const;

protected:
	template<class T> friend  class LuaClass;
	friend class LuaObjectImpl;
	LuaObjectImpl * m_ptr;
};


LUAOBJ_API extern LuaObject luaNil;//lua nil

namespace StackOps
{
	inline void Push(lua_State* L, LuaObject value) {
		if (value.isNone())
			lua_pushnil(L);
		else
			lua_pushvalue(L, value.getIndex());
	}
}

template <class T>
bool LuaObject::setUpValue(int n, T arg) {
	if (isFunction()) {
		lua_State* L = getLuaState();
		StackOps::Push(L, arg);
		if (lua_setupvalue(L, getIndex(), n)) {
			return true;
		}
		else {
			lua_pop(L, 1);
			return false;
		}
	}
	else {
		return false;
	}
}
